﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CollectableCollection.cs" company="JDML Consulting Ltd.">
//   Copyright 2011 Photon Project - http://photon.codeplex.com
// </copyright>
// <summary>
//   Defines the CollectableCollection type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Photon.Assets
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using Photon.Collections;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    public class CollectableCollection<T> : IEnumerable<T> where T : class
    {
        private readonly WeakReference[] _instanceReferences;
        private readonly T[] _instances;

        public CollectableCollection(int size, Func<T> factory) : this(new byte[size].Select(x => factory()).ToArray())
        {
        }

        public CollectableCollection(params T[] instances)
        {
            _instances = (T[])instances.Clone();
            _instanceReferences = instances.Select(x => new WeakReference(x)).ToArray();
        }

        public T this[int index]
        {
            get { return _instances[index]; }
        }

        public int Count
        {
            get { return _instances.Count(); }
        }

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            return ((IEnumerable<T>)_instances).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion

        public void Collect(params int[] indices)
        {
            // clear instances
            indices.ForEach(index =>
                {
                    if (_instances[index] == null)
                    {
                        throw new InvalidOperationException("Subscriber has already been collected.");
                    }
                    _instances[index] = null;
                });

            // collect
            GC.Collect();

            //verify
            indices.ForEach(index => Assert.IsFalse(_instanceReferences[index].IsAlive, "Instance was not collected."));
        }
    }
}